fix(companion): event type links for org user#20
Conversation
Addresses Cubic AI review feedback (confidence 9/10): The username was hardcoded to 'username' but still used by BasicsTab as a fallback for URL display when bookingUrl is unavailable. This restores the useEffect that fetches the actual username from CalComAPIService.getUsername(). Co-Authored-By: unknown <>
Code Review by Qodo
1. getUsername() throws generic Error
|
| // Helper to get username | ||
| async function getUsername(): Promise<string> { | ||
| try { | ||
| const profile = await getUserProfile(); | ||
| return profile.username; | ||
| } catch (error) { | ||
| throw new Error("Failed to get username"); | ||
| } | ||
| } |
There was a problem hiding this comment.
1. getusername() throws generic error 📘 Rule violation ⛯ Reliability
• getUsername() catches an unknown failure from getUserProfile() and throws a generic Error without a typed code/status or structured context, which makes downstream handling and debugging inconsistent. • The original error is discarded, so callers lose the root-cause details (and cannot reliably branch on error type), reducing robustness of error handling.
Agent prompt
## Issue description
`getUsername()` throws a generic `Error("Failed to get username")` and drops the original exception, violating the requirement for hierarchical typed errors with context.
## Issue Context
This is a core service helper; callers need consistent error types/codes and the original cause for debugging and reliable handling.
## Fix Focus Areas
- companion/services/calcom.ts[1654-1662]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const handlePreview = async (eventType: EventType) => { | ||
| if (!eventType.bookingUrl) { | ||
| showErrorAlert("Error", "Booking URL not available for this event type."); | ||
| return; | ||
| } | ||
| try { | ||
| const link = await CalComAPIService.buildEventTypeLink(eventType.slug); | ||
| // Open in browser | ||
| if (Platform.OS === "web") { | ||
| window.open(link, "_blank"); | ||
| window.open(eventType.bookingUrl, "_blank"); | ||
| } else { | ||
| // For mobile, use in-app browser | ||
| await openInAppBrowser(link, "event type preview"); | ||
| await openInAppBrowser(eventType.bookingUrl, "event type preview"); | ||
| } |
There was a problem hiding this comment.
2. Unvalidated bookingurl navigation 📘 Rule violation ⛨ Security
• The code uses eventType.bookingUrl (originating from external/API data) directly in navigation actions like window.open(...) / openInAppBrowser(...) without validating scheme/host, which can enable opening attacker-controlled URLs. • This violates the requirement that external inputs are validated/sanitized before use, especially when used for navigation and data handling.
Agent prompt
## Issue description
`bookingUrl` is treated as a trusted full URL and opened directly in browser contexts without validation.
## Issue Context
`bookingUrl` is API-provided (external input). Navigation actions should only allow expected schemes/hosts (e.g., https + cal.com domains) and reject/replace anything else.
## Fix Focus Areas
- companion/app/(tabs)/(event-types)/index.tsx[287-297]
- companion/extension/entrypoints/content.ts[1079-1087]
- companion/extension/lib/linkedin.ts[667-672]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| if (!bookingUrl) { | ||
| showErrorAlert("Error", "Booking URL not available. Please save the event type first."); | ||
| return; | ||
| } | ||
| await openInAppBrowser(link, "event type preview"); | ||
| await openInAppBrowser(bookingUrl, "event type preview"); | ||
| }; | ||
|
|
||
| const handleCopyLink = async () => { | ||
| const eventTypeSlug = eventSlug || "event-link"; | ||
| let link: string; | ||
| try { | ||
| link = await CalComAPIService.buildEventTypeLink(eventTypeSlug); | ||
| } catch (error) { | ||
| safeLogError("Failed to copy link:", error); | ||
| showErrorAlert("Error", "Failed to copy link. Please try again."); | ||
| if (!bookingUrl) { | ||
| showErrorAlert("Error", "Booking URL not available. Please save the event type first."); | ||
| return; | ||
| } | ||
| await Clipboard.setStringAsync(link); | ||
| await Clipboard.setStringAsync(bookingUrl); | ||
| showSuccessAlert("Success", "Link copied!"); | ||
| }; |
There was a problem hiding this comment.
3. Booking url never populated 🐞 Bug ✓ Correctness
• EventTypeDetail now gates Preview/Copy on a local bookingUrl state, but the state is initialized empty and is never set from fetched event type data. • As a result, Preview/Copy will always show “Booking URL not available…” even for existing event types. • This is a functional regression that blocks core actions on the Event Type detail screen.
Agent prompt
### Issue description
`EventTypeDetail` introduced a `bookingUrl` state and now blocks Preview/Copy unless it is non-empty. However, `bookingUrl` is never set from fetched event type data, so the Preview/Copy actions always error.
### Issue Context
- `fetchEventTypeData()` fetches an `EventType` and calls `applyEventTypeData(eventType)`.
- `applyEventTypeData()` sets many UI states (title/slug/hidden/etc.) but does not set `bookingUrl`.
- `handlePreview` / `handleCopyLink` require `bookingUrl`.
### Fix Focus Areas
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-520]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[826-840]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]
### Suggested implementation notes
- In `applyEventTypeData(eventType)`, add `setBookingUrl(eventType.bookingUrl ?? "")`.
- Consider a safe fallback for preview/copy when `eventType.bookingUrl` is absent, e.g. `https://cal.com/${username}/${eventType.slug}` (using already-fetched `username` state) or the pre-existing behavior.
- Ensure `bookingUrl` is refreshed after save/refresh (it already calls `fetchEventTypeData()` after update).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Benchmark PR from agentic-review-benchmarks#5